//! # 认证服务核心实现
//!
//! 提供统一的认证授权服务，支持多种认证提供者的组合使用。

use std::sync::Arc;
use std::collections::HashMap;
use async_trait::async_trait;
use rustcloud_security::prelude::*;
use crate::service::{AuthServiceConfig, AuthProviderInfo};

#[cfg(feature = "rbac")]
use crate::rbac::PolicyEngine;

#[cfg(feature = "audit")]
use crate::audit::{SecurityAuditor, SecurityEventType, AuthEventType, AuthzEventType, EventResult};

/// 认证服务
///
/// 整合多种认证提供者，提供统一的认证授权接口
pub struct AuthService {
    /// 配置
    config: AuthServiceConfig,
    /// 认证提供者集合
    providers: HashMap<String, Arc<dyn AuthProvider>>,
    /// 默认权限检查器
    permission_checker: Arc<dyn PermissionChecker>,
    /// 会话管理器（可选）
    session_manager: Option<Arc<dyn SessionManager>>,
    /// RBAC 策略引擎（可选）
    #[cfg(feature = "rbac")]
    policy_engine: Option<Arc<PolicyEngine>>,
    /// 安全审计器（可选）
    #[cfg(feature = "audit")]
    auditor: Option<Arc<SecurityAuditor>>,
}

impl AuthService {
    /// 创建新的认证服务实例
    pub fn new(
        config: AuthServiceConfig,
        providers: HashMap<String, Arc<dyn AuthProvider>>,
        permission_checker: Arc<dyn PermissionChecker>,
    ) -> Self {
        Self {
            config,
            providers,
            permission_checker,
            session_manager: None,
            #[cfg(feature = "rbac")]
            policy_engine: None,
            #[cfg(feature = "audit")]
            auditor: None,
        }
    }

    /// 设置会话管理器
    pub fn with_session_manager(mut self, session_manager: Arc<dyn SessionManager>) -> Self {
        self.session_manager = Some(session_manager);
        self
    }

    /// 设置 RBAC 策略引擎
    #[cfg(feature = "rbac")]
    pub fn with_policy_engine(mut self, policy_engine: Arc<PolicyEngine>) -> Self {
        self.policy_engine = Some(policy_engine);
        self
    }

    /// 设置安全审计器
    #[cfg(feature = "audit")]
    pub fn with_auditor(mut self, auditor: Arc<SecurityAuditor>) -> Self {
        self.auditor = Some(auditor);
        self
    }

    /// 获取认证提供者
    pub fn get_provider(&self, name: &str) -> Option<&Arc<dyn AuthProvider>> {
        self.providers.get(name)
    }

    /// 获取默认认证提供者
    pub fn get_default_provider(&self) -> Option<&Arc<dyn AuthProvider>> {
        self.providers.get(&self.config.default_provider)
    }

    /// 根据上下文选择最佳认证提供者
    fn select_provider(&self, context: &AuthContext) -> Option<&Arc<dyn AuthProvider>> {
        // 1. 检查是否有Bearer令牌 -> JWT提供者
        if context.get_bearer_token().is_some() {
            if let Some(provider) = self.providers.get("jwt") {
                return Some(provider);
            }
        }

        // 2. 检查是否有API Key -> API Key提供者
        if context.get_api_key().is_some() {
            if let Some(provider) = self.providers.get("api_key") {
                return Some(provider);
            }
        }

        // 3. 检查是否有Basic认证 -> Basic提供者
        if context.get_basic_auth().is_some() {
            if let Some(provider) = self.providers.get("basic") {
                return Some(provider);
            }
        }

        // 4. 返回默认提供者
        self.get_default_provider()
    }

    /// 记录认证事件
    #[cfg(feature = "audit")]
    async fn audit_authentication(&self, context: &AuthContext, result: &AuthResult<Principal>) {
        if let Some(auditor) = &self.auditor {
            let event = crate::audit::AuthenticationEvent {
                timestamp: std::time::SystemTime::now(),
                source_ip: context.get_client_ip().map(|s| s.to_string()),
                user_agent: context.headers.get("user-agent")
                    .and_then(|v| v.to_str().ok())
                    .map(|s| s.to_string()),
                method: context.method.clone(),
                uri: context.uri.clone(),
                success: result.is_ok(),
                error_message: result.as_ref().err().map(|e| e.to_string()),
                user_id: result.as_ref().ok().map(|p| p.id.clone()),
            };

            if let Err(e) = auditor.log_authentication(event).await {
                tracing::warn!("Failed to audit authentication event: {}", e);
            }
        }
    }

    /// 记录授权事件
    #[cfg(feature = "audit")]
    async fn audit_authorization(
        &self,
        principal: &Principal,
        resource: &Resource,
        result: &AuthResult<bool>,
    ) {
        if let Some(auditor) = &self.auditor {
            let event = crate::audit::AuthorizationEvent {
                timestamp: std::time::SystemTime::now(),
                user_id: principal.id.clone(),
                resource_service: resource.service.clone(),
                resource_path: resource.path.clone(),
                resource_action: resource.action.clone(),
                success: result.as_ref().map(|&allowed| allowed).unwrap_or(false),
                error_message: result.as_ref().err().map(|e| e.to_string()),
            };

            if let Err(e) = auditor.log_authorization(event).await {
                tracing::warn!("Failed to audit authorization event: {}", e);
            }
        }
    }
}

#[async_trait]
impl AuthenticationService for AuthService {
    async fn authenticate(&self, context: &AuthContext) -> AuthResult<Principal> {
        tracing::debug!("Authenticating request: {} {}", context.method, context.uri);

        // 选择认证提供者
        let provider = self.select_provider(context)
            .ok_or_else(|| AuthError::ConfigurationError("No suitable authentication provider found".to_string()))?;

        // 执行认证
        let result = provider.authenticate(context).await;

        // 审计记录
        #[cfg(feature = "audit")]
        self.audit_authentication(context, &result).await;

        // 检查结果
        let principal = result?;

        // 检查主体是否过期
        if principal.is_expired() {
            return Err(AuthError::TokenExpired);
        }

        // 检查账户状态
        if principal.principal_type == PrincipalType::User {
            if let Some(disabled) = principal.attributes.get("disabled") {
                if disabled == "true" {
                    return Err(AuthError::AccountDisabled(principal.id.clone()));
                }
            }

            if let Some(locked) = principal.attributes.get("locked") {
                if locked == "true" {
                    return Err(AuthError::AccountLocked(principal.id.clone()));
                }
            }
        }

        tracing::info!("Successfully authenticated user: {}", principal.id);
        Ok(principal)
    }

    async fn authorize(&self, principal: &Principal, resource: &Resource) -> AuthResult<bool> {
        if !self.config.permission_enabled {
            return Ok(true);
        }

        tracing::debug!(
            "Authorizing user {} for resource: {} {} {}",
            principal.id,
            resource.service,
            resource.method,
            resource.path
        );

        // 使用权限检查器进行授权
        let result = self.permission_checker.check_resource(principal, resource).await;

        // 审计记录
        #[cfg(feature = "audit")]
        self.audit_authorization(principal, resource, &result).await;

        let authorized = result?;

        if authorized {
            tracing::debug!(
                "User {} authorized for resource: {} {} {}",
                principal.id,
                resource.service,
                resource.method,
                resource.path
            );
        } else {
            tracing::warn!(
                "User {} denied access to resource: {} {} {}",
                principal.id,
                resource.service,
                resource.method,
                resource.path
            );
        }

        Ok(authorized)
    }

    async fn refresh_token(&self, refresh_token: &str) -> AuthResult<String> {
        // 尝试使用支持令牌刷新的提供者
        for provider in self.providers.values() {
            if provider.supports_token_refresh() {
                match provider.refresh_token(refresh_token).await {
                    Ok(new_token) => {
                        tracing::info!("Successfully refreshed token");
                        return Ok(new_token);
                    }
                    Err(AuthError::InvalidToken(_)) | Err(AuthError::TokenExpired) => {
                        // 继续尝试下一个提供者
                        continue;
                    }
                    Err(e) => return Err(e),
                }
            }
        }

        Err(AuthError::UnsupportedOperation("Token refresh not supported by any provider".to_string()))
    }

    async fn logout(&self, principal: &Principal) -> AuthResult<()> {
        tracing::info!("Logging out user: {}", principal.id);

        // 从所有提供者中注销
        for provider in self.providers.values() {
            if let Err(e) = provider.logout(principal).await {
                tracing::warn!("Failed to logout from provider {}: {}", provider.provider_name(), e);
            }
        }

        // 清理会话
        if let Some(session_manager) = &self.session_manager {
            if let Err(e) = session_manager.delete_user_sessions(&principal.id).await {
                tracing::warn!("Failed to clean up sessions for user {}: {}", principal.id, e);
            }
        }

        Ok(())
    }

    async fn validate_session(&self, session_id: &str) -> AuthResult<Principal> {
        if let Some(session_manager) = &self.session_manager {
            session_manager.get_session(session_id).await
        } else {
            Err(AuthError::UnsupportedOperation("Session management not enabled".to_string()))
        }
    }
}

impl AuthService {
    /// 获取用户信息
    pub async fn get_user_info(&self, principal: &Principal) -> AuthResult<serde_json::Value> {
        // 尝试从认证提供者获取详细用户信息
        if let Some(provider) = self.get_default_provider() {
            provider.get_user_info(principal).await
        } else {
            // 返回基本信息
            Ok(serde_json::json!({
                "id": principal.id,
                "name": principal.name,
                "type": principal.principal_type,
                "roles": principal.roles,
                "permissions": principal.permissions,
                "attributes": principal.attributes
            }))
        }
    }

    /// 检查用户权限
    pub async fn check_permission(&self, principal: &Principal, permission: &str) -> AuthResult<bool> {
        self.permission_checker.check(principal, permission).await
    }

    /// 获取用户所有权限
    pub async fn get_user_permissions(&self, principal: &Principal) -> AuthResult<Vec<String>> {
        Ok(principal.get_permissions().iter().map(|s| s.to_string()).collect())
    }

    /// 获取配置信息
    pub fn get_config(&self) -> &AuthServiceConfig {
        &self.config
    }

    /// 获取已注册的提供者列表
    pub fn list_providers(&self) -> Vec<String> {
        self.providers.keys().cloned().collect()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::HashMap;

    // Mock权限检查器
    struct MockPermissionChecker;

    #[async_trait]
    impl PermissionChecker for MockPermissionChecker {
        async fn check(&self, _principal: &Principal, _permission: &str) -> AuthResult<bool> {
            Ok(true)
        }

        async fn check_resource(&self, _principal: &Principal, _resource: &Resource) -> AuthResult<bool> {
            Ok(true)
        }

        async fn check_multiple(&self, _principal: &Principal, _permissions: &[&str]) -> AuthResult<Vec<bool>> {
            Ok(vec![true; _permissions.len()])
        }

        async fn check_any(&self, _principal: &Principal, _permissions: &[&str]) -> AuthResult<bool> {
            Ok(true)
        }

        async fn check_all(&self, _principal: &Principal, _permissions: &[&str]) -> AuthResult<bool> {
            Ok(true)
        }
    }

    // Mock认证提供者
    struct MockAuthProvider {
        name: String,
        should_authenticate: bool,
    }

    impl MockAuthProvider {
        fn new(name: &str, should_authenticate: bool) -> Self {
            Self {
                name: name.to_string(),
                should_authenticate,
            }
        }
    }

    #[async_trait]
    impl AuthProvider for MockAuthProvider {
        async fn authenticate(&self, _context: &AuthContext) -> AuthResult<Principal> {
            if self.should_authenticate {
                Ok(Principal::new(
                    "test_user".to_string(),
                    "Test User".to_string(),
                    PrincipalType::User,
                ))
            } else {
                Err(AuthError::AuthenticationFailed("Mock failure".to_string()))
            }
        }

        async fn validate_token(&self, _token: &str) -> AuthResult<bool> {
            Ok(self.should_authenticate)
        }

        fn provider_type(&self) -> AuthProviderType {
            AuthProviderType::Custom(self.name.clone())
        }

        fn provider_name(&self) -> &str {
            &self.name
        }
    }

    #[tokio::test]
    async fn test_auth_service_authenticate_success() {
        let config = AuthServiceConfig::default();
        let mut providers = HashMap::new();
        providers.insert("jwt".to_string(), Arc::new(MockAuthProvider::new("jwt", true)) as Arc<dyn AuthProvider>);
        
        let permission_checker = Arc::new(MockPermissionChecker);
        let auth_service = AuthService::new(config, providers, permission_checker);

        let context = AuthContext::new(
            Default::default(),
            "GET".to_string(),
            "/api/test".to_string(),
            Some("127.0.0.1".to_string()),
        );

        let result = auth_service.authenticate(&context).await;
        assert!(result.is_ok());
    }

    #[tokio::test]
    async fn test_auth_service_authorize_success() {
        let config = AuthServiceConfig::default();
        let providers = HashMap::new();
        let permission_checker = Arc::new(MockPermissionChecker);
        let auth_service = AuthService::new(config, providers, permission_checker);

        let principal = Principal::new(
            "test_user".to_string(),
            "Test User".to_string(),
            PrincipalType::User,
        );
        let resource = Resource::new(
            "test-service".to_string(),
            "/api/test".to_string(),
            "GET".to_string(),
        );

        let result = auth_service.authorize(&principal, &resource).await;
        assert!(result.is_ok());
        assert!(result.unwrap());
    }
}